package com.meituan.banma.common.net.request;

import android.net.Uri;
import android.text.TextUtils;

import com.alibaba.fastjson.JSON;
import com.meituan.banma.analytics.CATMonitorService;
import com.meituan.banma.base.net.BanmaNetManager;
import com.meituan.banma.base.net.antiReptile.CustomData;
import com.meituan.banma.base.net.setKey.SetKeyModel;
import com.meituan.banma.common.net.TraceId;
import com.meituan.banma.common.net.listener.IResponseListener;
import com.meituan.banma.common.net.response.MyResponse;
import com.meituan.banma.common.util.CommonUtil;
import com.meituan.banma.common.util.Constants;
import com.meituan.banma.main.bean.AppInfo;
import com.meituan.banma.main.model.AppPrefs;
import com.meituan.banma.monitor.IndividualAbnormalMonitor;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.Map;

/**
 * Created by zhengxiaoqiang on 15/3/6.
 * <p>
 * Updated by lilanhui on 18/9/27.
 * 在url的query中增加setKey参数（post的body不增加该参数）
 * https://km.sankuai.com/page/71506799
 */
public abstract class MyRequest {

    private static final String TAG = "MyRequest";

    private String mRelativeUrl;
    private HashMap<String, String> mParams = new HashMap<>();

    private IResponseListener mResponseListener;

    private String requestTag;

    //__skbk = (美团众包x.x.x).MD5 16位 大写
    //工具网址：https://md5jiami.51240.com/
    //注意：使用同一个网址工具进行MD5值计算，不然可能出现结果不一致
    public static String XXYY = "6AC0ED42A41CA8A4";

    /*
    代表app versioncode的转义，对应关系见下
    0 -- 0
    1 -- A
    2 -- B
    3 -- C
    4 -- D
    5 -- E
    6 -- F
    7 -- G
    8 -- H
    9 -- I
    如 versioncode=430 则为DC0
    必须硬编码，禁止通过函数取版本号
    */
    public static String VCODE = "BDGE";
    public final static int TIMEOUT = 20 * 1000;
    /**
     * 表示该请求走长链接SDK
     */
    private boolean execByShark = false;
    /*--------------- CAT 采集参数 ---------------*/
    /**
     * 采样率, 短连接上也需要做采样率处理
     */
    public int sampling = 100;
    public long requestTime;
    public int requestBytes;
    public int responseBytes;
    public int responseTime;
    public String command;
    /*--------------- CAT 采集参数 ---------------*/
    protected boolean isFailOver = false;
    public static boolean isV = false;

    public MyRequest(String relativeUrl, IResponseListener listener) {

        mRelativeUrl = relativeUrl;
        mResponseListener = listener;

        //add common parameters
        addCommonParams();
    }

    protected String buildFullUrl() {
        return BanmaNetManager.getBaseBanmaHttpConfig().getCurrentUseHost() + mRelativeUrl;
    }

    public int getMethod() {
        //default is POST method
        // GET = 0, POST = 1
        return 1;
    }

    protected boolean enableSignature() {
        return false;
    }

    /**
     * 开放给外部类，请求是否需要验签
     *
     * @return
     */
    public boolean getSignarureState() {
        return enableSignature();
    }

    /**
     * 支撑装备商城详情页以POST方式打开网页
     * 方法来自Volley的Request
     *
     * @return
     */
    public byte[] getBody() {
        Map<String, String> params = getParams();
        if (params != null && params.size() > 0) {
            return encodeParameters(params, "UTF-8");
        }
        return null;
    }

    /**
     * 支撑装备商城详情页以POST方式打开网页
     * 方法来自Volley的Request
     * Converts <code>params</code> into an application/x-www-form-urlencoded encoded string.
     */
    private byte[] encodeParameters(Map<String, String> params, String paramsEncoding) {
        StringBuilder encodedParams = new StringBuilder();
        try {
            for (Map.Entry<String, String> entry : params.entrySet()) {
                encodedParams.append(URLEncoder.encode(entry.getKey(), paramsEncoding));
                encodedParams.append('=');
                encodedParams.append(URLEncoder.encode(entry.getValue(), paramsEncoding));
                encodedParams.append('&');
            }
            return encodedParams.toString().getBytes(paramsEncoding);
        } catch (UnsupportedEncodingException uee) {
            throw new RuntimeException("Encoding not supported: " + paramsEncoding, uee);
        }
    }

    /**
     * 开放给外部检查完整的url请求
     *
     * @param url
     * @return
     */
    public String getFullUrlWithParams(String url) {
        if (!TextUtils.isEmpty(url)) {
            long time = System.currentTimeMillis();
            String skbk = getSKBK(time);
            String params = "a=" + Constants.type + "&v=" + AppInfo.appVersion + "&m=" + AppPrefs.getUserId() + "&__skbk=" + skbk + "&time=" + time;

            if (isV) {
                params += "&o=3";
            } else {
                params += "&o=1";
            }
            params += "&setKey=" + SetKeyModel.getLocalSetKey(AppPrefs.getUserId());//R端路由
            params += "&ci=" + AppPrefs.getRiderWorkingCityId(); // 工作城市id
            if (url.contains("?")) {
                url += "&" + params;
            } else {
                url += "?" + params;
            }
        }
        return url;
    }

    public String getFullUrlWithParams() {
        Uri.Builder builder = Uri.parse(buildFullUrl()).buildUpon();
        for (Map.Entry<String, String> entry : mParams.entrySet()) {
            builder.appendQueryParameter(entry.getKey(), entry.getValue());
        }
        String queryString = builder.build().toString();
        return queryString;
    }
    public static String getSKBK(long time) {
        return CommonUtil.MD5(time + "|" + XXYY + "|" + VCODE);
    }

    public IResponseListener getResponseListener() {
        return mResponseListener;
    }

    //subclass need override this parse their own data field
    protected Object parseResponseDataField(String data) {
        return data;
    }

    //subclass could override this to parse the raw response string
    protected MyResponse parseMyResponse(String data) {
        InnerResponse ir = JSON.parseObject(data, InnerResponse.class);

        MyResponse response = new MyResponse();
        response.code = ir.code;
        response.msg = ir.msg;
        response.action = ir.action;
        response.customData = ir.customData;

        if (ir.code == 0) {
            //success
            response.data = parseResponseDataField(ir.data);
            IndividualAbnormalMonitor.appRequestDataMonitor(getRelativeUrl(), response.data);
        }
        return response;
    }

    /**
     * 开放给适配器调用，把原始String映射为子类定义的数据对象
     *
     * @param data
     * @return
     */
    public MyResponse parseMyResponseForAdapter(String data) {
        return parseMyResponse(data);
    }

    protected void addCommonParams() {
        //default no common params
        //subclass can override this to add common params
    }

    public void addParam(String name, String value) {
        if (!TextUtils.isEmpty(name)) {
            mParams.put(name, value == null ? "" : value);
        }
    }

    protected void addParam(String name, int value) {
        if (!TextUtils.isEmpty(name)) {
            mParams.put(name, String.valueOf(value));
        }
    }

    protected void addParam(String name, long value) {
        if (!TextUtils.isEmpty(name)) {
            mParams.put(name, String.valueOf(value));
        }
    }

    protected void addParam(String name, double value) {
        if (!TextUtils.isEmpty(name)) {
            mParams.put(name, String.valueOf(value));
        }
    }

    public String getRelativeUrl() {
        return mRelativeUrl;
    }

    public String getFullUrl() {
        return buildFullUrl();
    }

    public Map<String, String> getParams() {
        return mParams;
    }

    public Map<String, String> getHeaders() {
        Map<String, String> headers = new HashMap<>();
        headers.put(TraceId.TAG, TraceId.get());
        return headers;
    }

    public String getRequestTag() {
        return requestTag;
    }

    public void setRequestTag(String requestTag) {
        this.requestTag = requestTag;
    }

    protected void catLogWithCode(int code) {
        IndividualAbnormalMonitor.appRequestCodeMonitor(getRelativeUrl(), code);

        // 由shark sdk上报, 不自己上报CAT监控数据
        if (execByShark) {
            return;
        }

        if (CATMonitorService.getInstance() == null) {
            return;
        }

        int tunnel = !TextUtils.isEmpty(command) && command.startsWith("https") ? 8 : 0;
        CATMonitorService.getInstance().catLog(requestTime, command, 0, tunnel, code, requestBytes, responseBytes, responseTime, null, sampling);
    }

    private static class InnerResponse {
        public int code;
        public String msg;
        public String data;
        public String action;//动态路由协议

        /**
         * 反爬服务MTSI返回的数据，目前用于解析命中反爬策略后yoda弹窗所需的requestCode<p>
         * https://km.sankuai.com/page/163524182
         */
        public CustomData customData;

        public String getAction() {
            return action;
        }

        public void setAction(String action) {
            this.action = action;
        }

        public InnerResponse() {
        }

        public String getMsg() {
            return msg;
        }

        public void setMsg(String msg) {
            this.msg = msg;
        }

        public String getData() {
            return data;
        }

        public void setData(String data) {
            this.data = data;
        }

        public int getCode() {
            return code;
        }

        public void setCode(int code) {
            this.code = code;
        }
    }


}
